package android.javaClasses;

import android.util.Log;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketException;

/**
 * Created by IntelliJ IDEA.
 * User: michelle
 * Date: 4/25/11
 * Time: 1:45 PM
 * To change this template use File | Settings | File Templates.
 */
public class Stream {
    private Socket socket;
    private OnCloseStreamListener closeListener;
    private OnReadObjectListener readListener;
    private ObjectInputStream in;
    private ObjectOutputStream out;
    private Thread thread;
    private boolean reading;

    public static interface OnReadObjectListener {
        void onReadObject(Content content);
    }

    public static interface OnCloseStreamListener{
        void onCloseStream();
    }

    //Used by the receiver to create an input socket
    public Stream(Socket socket) {
        this.socket = socket;
        try {
            out = new ObjectOutputStream(socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //Used by the user to create an output socket, when the client wants to create a socket with the server
    public Stream(String ip, int port) {
        try {
            socket = new Socket(ip, port);
            out = new ObjectOutputStream(socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setOnReadObjectListener(OnReadObjectListener listener) {
        readListener = listener;
    }

    public void setOnCloseStreamListener(OnCloseStreamListener listener) {
        closeListener = listener;
    }

    /**
     * Starts a new thread which reads from the ObjectInputStream.
     * If the stream is empty
     */
    public synchronized void startReading() {
        if(thread != null) return;

        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    in = new ObjectInputStream(socket.getInputStream());
                    reading = true;
                    while(reading) {
                        Content content = null;
                        try {
                            Log.i("stream @server", "reading object");
                            content =(Content) in.readObject();
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                        if(content == null) {
                            Log.i("stream @server", "content is null");
                            //The other device has closed its socket stream
                            reading = false;
                            closeListener.onCloseStream();
                        } else {
                            Log.i("stream @server", "calling onReadObject");
                            readListener.onReadObject(content);
                        }
                    }
                } catch (SocketException e) {
                    e.printStackTrace();
                    //StopReading has been called
                } catch (IOException e) {
                    //Error handling
                    e.printStackTrace();
                }
            }
        });
        thread.start();
    }

    /**
     * Writes an object of type content to the stream.
     * @param content
     */
    public synchronized void writeObject(Content content) {
        try {
            out.writeObject(content);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public synchronized void close() {
        try {
            if(thread != null) {
                reading = false;
                socket.close();
                in.close();
                out.close();
                thread = null;
            } else {
                socket.close();
                in.close();
            }
        } catch(Exception e) {}
    }

}
